﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.IO;
using ServerCSharp.Database1DataSetTableAdapters;

namespace ServerCSharp
{
    class MyServer
    {
        private TcpListener listener;
        private Thread listenThread;
        private ArrayList veiculosConectados;

        public MyServer(Int16 port)
        {
            veiculosConectados = new ArrayList();
            Start(port);
        }

        public ArrayList VeiculosConectados
        {
            get
            {
                ArrayList list = veiculosConectados;
                return list;
            }
        }

        public ArrayList VeiculosDisponiveis
        {
            get
            {
                ArrayList listaFinal = new ArrayList();

                foreach (Veiculo veiculo in veiculosConectados)
                {
                    if (veiculo.Estado == Veiculo.Status.DISPONIVEL)
                    {
                        listaFinal.Add(veiculo);
                    }
                }

                return listaFinal;
            }
        }

        public void Start(Int16 port)
        {
            this.listener = new TcpListener(IPAddress.Any, port);
            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();
        }

        private void ListenForClients()
        {
            NetworkStream tStream;
            BinaryReader tReader;
            Int16 tID, tPos;
            Byte tStatus;
            this.listener.Start();

            while (true)
            {
                TcpClient tClient = this.listener.AcceptTcpClient();
                tStream = tClient.GetStream();
                tReader = new BinaryReader(tStream);

                tID = tReader.ReadInt16();
                tPos = tReader.ReadInt16();
                tStatus = tReader.ReadByte();

                Database1DataSet.VeículosDataTable obj = new Database1DataSet.VeículosDataTable();

                VeículosTableAdapter obj2 = new VeículosTableAdapter();

                obj = obj2.FindByID(tID);

                Int16 posicao = Int16.Parse(obj.Rows[0]["Posicao"].ToString());



                Veiculo veiculoConectado;

                lock (this)
                {
                    veiculoConectado = new Veiculo(tID, posicao, tStatus, tClient);
                }

                int index = FindByID(tID);

                if (index < 0)
                    veiculosConectados.Add(veiculoConectado);
                else
                    veiculosConectados[index] = veiculoConectado;
                
                Thread novaThread = new Thread(GerenciarVeiculoConectado);
                novaThread.Start(veiculoConectado);
            }
        }
        

        private void GerenciarVeiculoConectado(object obj)
        {
            Veiculo veiculoConectado = (Veiculo)obj;
            TcpClient client = veiculoConectado.ClientHandler;
            NetworkStream stream = client.GetStream();
            BinaryReader reader = new BinaryReader(stream);

            while (true)
            {
                Byte codigo;
                try
                {
                    codigo = reader.ReadByte();
                }
                catch(IOException)
                {
                    break;
                }

                if (codigo == 1)
                {
                    Byte status = reader.ReadByte();

                    if (status < 0)
                    {
                        stream.Close();
                        client.Close();
                        break;
                    }

                    else
                    {
                        lock (this)
                        {
                            veiculoConectado.Estado = (Veiculo.Status)status;
                        }
                    }
                }
                else if (codigo == 2)
                {
                    Int16 newPos = reader.ReadInt16();

                    lock (this)
                    {
                        veiculoConectado.UltPosicao = newPos;
                    }
                }
            }
            veiculosConectados.Remove(veiculoConectado);
        }


        private int FindByID(Int16 id)
        {
            int count = 0;
            foreach (Veiculo v in veiculosConectados)
            {
                if (v.ID== id)
                {
                    return count;
                }
                count++;
            }
            return -1;
        }

        

        public void AtualizarDestino(Veiculo veiculo, Int16 novoDestino)
        {
            if (veiculo.Estado == Veiculo.Status.DISPONIVEL)
            {
                TcpClient client = veiculo.ClientHandler;
                NetworkStream stream = client.GetStream();
                BinaryWriter writer = new BinaryWriter(stream);

                writer.Write(novoDestino);
            }
            else
                throw new Exception("Estado inválido para atualizar destino");
        }

        public void AtualizarDestino(Int32 idVeiculo, Int16 novoDestino)
        {
            Veiculo veiculo = (Veiculo)veiculosConectados[FindByID((Int16)idVeiculo)];
            AtualizarDestino(veiculo, novoDestino);
        }
    }
}
